home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / NDK / NDK_3.5 / Tools / ReActor / Examples / EuroCalc / EuroCalc.dok < prev    next >
Encoding:
Text File  |  1999-10-25  |  11.1 KB  |  223 lines

  1. Programmier-Beschreibung zum Programm "EuroCalc":
  2. =================================================
  3. von Michael Christoph <michael@meicky-soft.de>
  4.  
  5. AmigaOS 3.5 bringt eine umfangreiche Sammlung an BOOPSI-Klassen mit,
  6. welche mit ReActor komfortabel zu einer Oberfläche zusammengestellt
  7. werden können. Dabei ist die Oberfläche komplett selbstlayoutend
  8. und paßt sich somit unterschiedlichen Fontgrößen ebenso an wie
  9. unterschiedlichen (Localen) Texten für die einzelnen Elemente.
  10.  
  11. Anhand eines kleinen Beispielprogramms wird gezeigt, wie diese
  12. Oberflächen in den eigenen Quellcode einzubinden sind und wie der
  13. Datenaustausch mit den Elementen (Gadgets, Windows) funktioniert.
  14.  
  15. Zuerst wird die Oberfläche mit dem Programm "ReActor" erstellt. Dabei
  16. werden die einzelnen Gadgets nicht mehr wie früher üblich, pixelweise
  17. positioniert, sondern das Layout mittels horizontaler und vertikaler
  18. Gruppen "beschrieben". Das kann zwar teilweise den Nachteil haben, daß
  19. einzelne Gadgets nicht mehr genau positioniert werden können, auf der
  20. anderen Seite dürfte aber das komplett automatisch ablaufende layouten
  21. aller Gadgets einen großen Vorteil bieten. Wurden früher die Fensterinhalte
  22. starr auf einen Font ausgerichtet, um den notwendigen Aufwand des variablen
  23. Layouts zu umgehen, gehört dieser Punkt nun der Vergangenheit an. Der
  24. Programmierer kann sich somit um die eigentlichen Programm-Aufgaben kümmern
  25. und braucht kaum noch Zeit zum Erstellen der zugehörigen Benutzeroberfläche.
  26.  
  27. Für den geplanten Euro-Währungsrechner, soll die Eingabe einer beliebigen
  28. Währung möglich sein, die dann in alle anderen Währungen umgerechnet und
  29. angezeigt wird. Somit wird also pro Währung ein Eingabefeld benötigt, daß
  30. mit der entsprechenden Währungsbezeichnung und dem Ländernamen gekennzeichnet
  31. wird. Zusätzlich soll auch die Länderfahne mit abgebildet werden (Image).
  32. Pro Währung ist also eine horizontale Gruppe zu erstellen, die zuerst eine
  33. PenMap (mit der Grafik), dann das Eingabefeld mit angehängtem Label und ganz
  34. rechts noch ein seperates Label für das Währungskennzeichen enthält.
  35. Die Benutzung der PenMap hat den vorteil, daß die Grafik, bei Bedarf,
  36. automatisch auf die Bildschirmfarben angepaßt wird.
  37. Diese zwölf horizontale Gruppen (für die 11 Teilnehmerländer und eine Zeile
  38. für den Euro-Wert) werden in einer vertikal Gruppe zusammengefast, welche im
  39. Fenster verankert wird.
  40. Auf die genaue Bedienung von ReActor und dem Erstellen dieser Oberfläche
  41. wird hier nicht weiter eingegangen. Lesen Sie hierzu bei Bedarf in der Anleitung
  42. zu ReActor nach.
  43. Die fertige Oberflächenbeschreibung liegt in der Datei "EuroCalcFrame.res" vor.
  44.  
  45. Nach dem Programmstart muß sofort überprüft werden, ob AmigaOS 3.5 und somit die
  46. benötigten Resourcen vorhanden sind. Das geschieht am einfachsten, indem die
  47. später noch benötigte "resource.library" geöffnet wird. Dabei ist auf Version 44
  48. zu prüfen (was AmigaOS 3.5 entspricht).
  49. Im Erfolgsfall können die weiter benötigten Libraries geöffnet werden (z.B.
  50. locale.library). Je nach verwendetem Compiler werden die benutzten Libraries
  51. automatisch geöffnet. In diesem Fall muß ein direkter Vergleich der Versionsnummer
  52. stattfinden:
  53.  
  54.   if(ResourceBase->lib_Version >= 44)
  55.     /* weiter im Programm ... */
  56.   else printf("ERROR: workbench 3.5 is required.\n");
  57.  
  58. Es ist zwar kein Catalog notwendig, er sollte aber trotzdem programmseitig immer
  59. geöffnet werden, um evtl. zukünftig erstellte Cataloge ohne Programmänderung
  60. verwenden zu können. Dann ist der zu benutzdende Bildschirm festzulegen. Entweder
  61. wird einfach der Workbench (bzw. Default-Public-Screen) verwendet, oder das
  62. Programm öffnet einen eigenen Bildschirm.
  63. Ein Zeiger auf diesen Screen und den Catalog werden dann an RL_OpenResource übergeben.
  64. Als erster Parameter wird 'RCTResource' erwartet. Dabei handelt es sich um eine
  65. globale Variable, die von ReActor mit in die Oberflächenbeschreibungsdatei
  66. eingebunden wird. RL_OpenResource() liefert einen Zeiger auf die erstellte
  67. Resource-Umgebung, der bei den weiteren Aufrufen noch benötigt wird.
  68. Zur Zeit müssen außerdem noch zwei Messageports für die interne Kommunikation
  69. (der Oberflächenelemente) erzeugt werden. Diese werden programmseitig normalerweise
  70. nicht benötigt und sollen in Zukunft automatisch von RL_OpenResource erzeugt werden.
  71. Über RL_NewObject() werden neue Objekte angefordert/reserviert. Dabei handelt es
  72. sich um die in ReActor erstellen Fenster- oder Gadgetgruppen, welche über die ID
  73. bestimmt werden. Soll auf die Gadgeteingaben vom Programm reagiert werden, müssen
  74. die einzelnen Gadget-Objekte bekannt sein. RL_GetObjectArray() liefert ein Array
  75. mit den entsprechenden Gadget-Zeigern. Anhand der IDs (aus der automatisch erzeugen
  76. Datei "EuroCalcFrame.h") kann dann gezielt auf ein Gadgetobjekt zugeriffen werden
  77. (z.B. gb_Gadgets[GAD_ID_EUR]). Danach wird die Menübeschreibung evtl. lokalisiert
  78. und das Menü erzeugt.
  79.  
  80. Damit sind alle Vorbereitungsarbeiten abgeschlossen und das Fenster kann geöffnet
  81. werden. Dazu dient das Kommando WM_OPEN, daß mittels DoMethod() abgesetzt wird.
  82. Alternativ können auch die sprechenderen Defines aus "classact_macros.h" verwendet
  83. werden (hier CA_OpenWindow mit dem Window-Objekt).
  84. Beachten Sie unbedingt, daß es sich bei den Objekt-Zeigern um klasseneigene, meißt
  85. nicht näher beschriebene Strukturen handelt. Wollen Sie direkt auf die Fenster-
  86. daten (struct Window *) zugreifen, so ist diese Zeiger erst mittels 
  87.  GetAttr(WINDOW_Window,gb_WindowObj,&gb_Window)
  88. anzufordern (bzw. wird bei WM_OPEN auch als Returnwert geliefert). Die beiden
  89. Zeiger dürfen auf keinen Fall vertauscht benutzt werden ! 'gb_Window' enthält
  90. die altbekannte Windows-Struktur, während 'gb_WindowObj' das Fenster-Objekt
  91. repräsentiert. Bei allen Intuition-Funktionen ist, wie bisher auch, der
  92. 'struct Window *' (also gb_Window) zu übergeben, während die Objektmethoden
  93. (DoMethod, GetAttr, SetAttr) nach einem Objekt (hier gb_WindowObj) verlangen.
  94.  
  95. Den normalen Programmlauf bestimmt der Messageloop. Dieser ist wieder speziell
  96. auf die ReActor-Umgebung anzupassen, da z.B. die Gadgetshotcuts automatisch
  97. behandelt werden. Auch bei Größenänderungen des Fensters, werden die enthaltenen
  98. Gadgets automatisch neu positioniert/angepaßt. Ebenso wird eine Refreshanforderung
  99. automatisch an die Gadgets weitergegeben. Das Programm braucht sich also
  100. (normalerweise) um viele Dinge nicht mehr zu kümmern!
  101.  
  102. Aus Zukunftskompatibilität sollte das Messagebit nicht direkt aus der
  103. Windows-Struktur ausgelesen werden, sondern beim Window-Objekt erfragt werden:
  104.  
  105.   ULONG windowsignal;
  106.   GetAttr(WINDOW_SigMask,gb_WindowObj,&windowsignal);
  107.  
  108. Dieses Bit wird wie bisher auch, mit den anderen Signalbits verodert, auf deren
  109. Ereignisse ebenfalls gewartet werden soll (andere Fenster, ARexx-Port, CTRL-C ect.).
  110. Beim Eintreffen von Nachrichten wird von Wait() das Fenstersignal (bzw. eines oder
  111. mehrere der anderen Signale) zurückgeliefert. Eine Auswertung der Nachrichten könnte
  112. wie folgt aussehen:
  113.  
  114.   ULONG result, code;
  115.   while((result = CA_HandleInput(gb_WindowObj,&code)) != WMHI_LASTMSG)  
  116.   {
  117.     switch(result & WMHI_CLASSMASK)
  118.     {
  119.       case WMHI_CLOSEWINDOW:
  120.            /* ... */
  121.            break;
  122.  
  123.       case WMHI_GADGETUP:
  124.            /* ... */
  125.            break;
  126.  
  127.       case WMHI_MENUPICK:
  128.            /* ... */
  129.            break;
  130.     }
  131.   }
  132.  
  133. Zu beachten ist, daß 'result' im oberen Word die Classe enthält und im unteren
  134. Word die Event-Daten. Daher muß der jeweils auszulesende Wert entsprechend
  135. maskiert werden.
  136. Die Gaddget-Gruppen-ID und normale Gadget-ID läst sich wie folgt ermitteln:
  137.  
  138.   const UWORD groupid  = RL_GROUPID(result);
  139.   const UWORD gadgetid = RL_GADGETID(result);
  140.  
  141. entsprechend die Menünummer über:
  142.  
  143.   const UWORD menunum = RL_MENUNUM(result);
  144.  
  145. und Tastencodes per
  146.  
  147.   const UBYTE keycode = RL_KEYCODE(result);
  148.  
  149. Zu beachten sind außerdem die beiden Returnwerte:
  150.   WMHI_LASTMSG (0) und WMHI_IGNORE (~0)
  151.  
  152. Bei ersterem liegt keine Nachricht mehr zur Verarbeitung vor, während bei letzterer
  153. die Nachricht nicht von der ReActor-Window-Classe verarbeitet werden konnte (was
  154. eigentlich nicht vorkommen kann).
  155.  
  156. Wurde in der Fensterbeschreibung WINDOW_Iconify gesetzt, so erhält das Fenster
  157. automatisch ein zusätzliches Gadget in der Titelzeile. Beim Anklicken wird eine
  158. Nachricht vom Typ WMHI_ICONIFY ausgelöst. Mittels CA_Iconify() wird das Fenster
  159. tatsächlich eingeklappt. Entsprechend öffnet CA_Uniconify() das Fenster wieder,
  160. wenn der Benutzer auf das Icon auf der Workbench Klickt (Nachricht WMHI_UNICONIFY
  161. wird geliefert).
  162. Jeweils nach dem Öffnen und Schließen des Fensters muß unbedingt die Variable
  163. gb_Window aktualisiert werden. Falls festgestellt werden soll, ob das Fenster
  164. momentan geschlossen ist, kann dies durch einen einfachen Vergleich von
  165. gb_Window == NULL erfolgen. Das Auslesen und Ändern der Werte in den Gadgets
  166. ist auch bei geschlossenem Fenster erlaubt, während die normalen Intuition-
  167. Funktion auf das Fenster natürlich nur dann angewendet werden dürfen, wenn das
  168. Fenster auch dargestellt wird.
  169. Während das Fenster iconifiziert ist, treffen auch keine Window/Gadget-Nachrichten
  170. ein, wodurch der Messageloop nicht speziell angepaßt oder reagieren muß.
  171.  
  172. In der weiteren Nachrichtenauswertung werden entsprechend dem Nachrichtentyp
  173. die verschiedenen Aktionen veranlast (Werte berechnen und anzeigen, Menüauswahl
  174. behandeln, Programm beenden, ect.).
  175.  
  176. Am Programmende sind in gewohnter Weise alle reservierten Resourcen wieder
  177. freizugeben. Für die komplette ReActor-Umgebung genügt ein Aufruf von
  178. RL_CloseResource(). Dieser gibt alle Fenster- und Gadgetobjekte frei.
  179. Sollen nur einzelne Gadgetgruppen bzw. Fenster freigegeben werden, so kann
  180. dazu RL_DisposeObject() verwendet werden. Normalerweise wird man jedoch beim
  181. Programmstart die benötigten Objekte mittels RL_NewObject() anlegen und
  182. am Programmende alle komplett durch RL_CloseResource() freigeben.
  183. Selten benötigte Fenster können aber in der Form 'Fensterobjekt anlegen - Fenster
  184. darstellen - Fensterobjekt freigeben' gehandhabt werden.
  185.  
  186. Danach ist/sind noch der Catalog und die Libraries zu schließen, sowie bei
  187. Bedarf ein Returncode für die Shell zu setzen.
  188.  
  189. Damit ist das Programm "EuroCalc" vollständig beschrieben. Weitere Erklärungen
  190. sind an den jeweiligen Stellen im Sourcecode angebracht, der keine
  191. "compilerspezifischen Eigenheiten" ausnutzt und daher mit jedem beliebigem
  192. Compiler übersetzbar sein sollte.
  193.  
  194. Mit ReActor generierte Oberflächen erhalten automatisch eine Datei mit den
  195. Localestrings (EuroCalcFrame.cd), welche zum Programmcode hinzugelinkt werden
  196. muß. Dazu ist zuerst mittels 'catcomprct' aus dieser Datei ein Assemblercode
  197. zu erzeugen, welcher assembliert ein Objektfile ergibt.
  198.  
  199. Das vollständige Compilieren setzt sich somit aus diesen vier Schritten zusammen
  200. (beispielhaft anhand des Maxon-Compilers dargestellt):
  201.  
  202. * compilieren des normalen Programmcodes:
  203.   mcppc3 -c EuroCalc.c
  204.  
  205. * Assemblercode der Localedatei erzeugen:
  206.   catcomprct EuroCalcFrame.cd
  207.  
  208. * die Localedatei assemblieren:
  209.   masm -c cl EuroCalcFrame_cd.asm
  210.  
  211. * und dann alles zusammenlinken:
  212.   mcppc3 EuroCalc.o EuroCalcFrame.o EuroCalcFrame_cd.o -o EuroCalc -l amiga
  213.  
  214.  
  215. --------------------------
  216. INFO zum restlichen Source:
  217. das Programm verwendet ein Array mit den Länderdaten, da hierdurch eine
  218. einfache for-Schleife für den Zugriff auf alle Gadgets benutzt werden kann.
  219. Zu beachten ist hierbei, daß das Array 0 unbenutzt bleibt und 1 mit der
  220. vertikalen Gruppe gesetzt ist und somit auch unbenutzt bleibt.
  221.  
  222.  
  223.